import defaultSettings from '~/defaultSettings'

interface fullScreenType {
  mozIsFullScreen: boolean
  webkitIsFullScreen: boolean
  isFullScreen: boolean
  exitFullScreen: () => void
  webkitCancelFullScreen: () => void
  mozCancelFullScreen: () => void
  documentElement: {
    requestFullScreen: () => void
    webkitRequestFullScreen: () => void
    mozRequestFullScreen: () => void
  }
}

// 定义阿里云验证类型防止ts抛异常
declare const document: Document & fullScreenType

// 表单序列化
export const serialize = (data: Record<string, any>) => {
  const list: string[] = []
  Object.keys(data).forEach((ele) => {
    list.push(`${ele}=${data[ele]}`)
  })
  return list.join('&')
}

// 获取对象类型
export const getObjType = (obj: any) => {
  const map = {
    '[object Boolean]': 'boolean',
    '[object Number]': 'number',
    '[object String]': 'string',
    '[object Function]': 'function',
    '[object Array]': 'array',
    '[object Date]': 'date',
    '[object RegExp]': 'regExp',
    '[object Undefined]': 'undefined',
    '[object Null]': 'null',
    '[object Object]': 'object'
  }
  if (obj instanceof Element) return 'element'
  return map[Object.prototype.toString.call(obj) as keyof typeof map]
}

/**
 * 设置灰度模式
 */
export const toggleGrayMode = () => {
  document.body.classList.toggle('grayMode')
}

/**
 * 设置主题
 */
export const setTheme = (name: string) => {
  document.body.classList.toggle(name)
}

/**
 * 加密处理
 */
// export const encryption = (params) => {
//   const { data, type, param, key } = params
//   const result = JSON.parse(JSON.stringify(data))
//   if (type === 'Base64') {
//     param.forEach(ele => {
//       result[ele] = window.btoa(result[ele])
//     })
//   } else if (type === 'Aes') {
//     param.forEach(ele => {
//       result[ele] = window.CryptoJS.AES.encrypt(result[ele], key).toString()
//     })
//   }
//   return result
// }

/**
 * 浏览器判断是否全屏
 */
export const fullscreenToggel = () => {
  if (fullscreenEnable()) {
    exitFullScreen()
  } else {
    reqFullScreen()
  }
}

/**
 * 浏览器判断是否全屏
 */
export const fullscreenEnable = () => {
  return (
    document.fullscreenEnabled ||
    document.mozIsFullScreen ||
    document.webkitIsFullScreen ||
    document.isFullScreen ||
    false
  )
}

/**
 * 浏览器全屏
 */
export const reqFullScreen = () => {
  if (document.documentElement.requestFullScreen) {
    document.documentElement.requestFullScreen()
  } else if (document.documentElement.webkitRequestFullScreen) {
    document.documentElement.webkitRequestFullScreen()
  } else if (document.documentElement.mozRequestFullScreen) {
    document.documentElement.mozRequestFullScreen()
  }
}

/**
 * 浏览器退出全屏
 */
export const exitFullScreen = () => {
  if (!document.documentElement.requestFullScreen === false) {
    document.exitFullScreen()
  } else if (!document.documentElement.webkitRequestFullScreen === false) {
    document.webkitCancelFullScreen()
  } else if (!document.documentElement.mozRequestFullScreen === false) {
    document.mozCancelFullScreen()
  }
}

/**
 * 动态插入css
 */
export const loadStyle = (url: string) => {
  const link = document.createElement('link')
  link.type = 'text/css'
  link.rel = 'stylesheet'
  link.href = url
  const head = document.getElementsByTagName('head')[0]
  head.appendChild(link)
}

/**
 * 获取顶部地址栏地址
 */
export const getTopUrl = () => {
  return window.location.origin
}

// 将数据字典过滤成枚举属性
export const filterValueEnum = <T>(arr: (Record<string, T> | T)[], key = 'key', value = 'value') =>
  arr?.reduce(
    (enumObj, item: Record<string, any>) =>
      Object.assign(
        enumObj,
        item?.[key] || (item?.[key] as any) === 0
          ? { [item?.[key] as unknown as string]: item?.[value] }
          : {}
      ),
    {}
  )

/**
 * 深度查找树级数组的每一项
 * @param arr 数组本身
 * @param key 需要匹配的key
 * @param childrenKey 如果有子集需要深度递归查询子集
 * @param value 需要匹配一致的value
 */
export const deepFindItemByKey = <T = any, S = string>(
  arr: T[],
  key: string,
  childrenKey: keyof T,
  value: S
): T | undefined => {
  for (let i = 0; i < arr.length; i++) {
    const item = arr[i]
    if ((item as any)?.[key] === value) {
      return item
    }
    if ((item[childrenKey] as any)?.length) {
      const findItem = deepFindItemByKey(item[childrenKey] as any, key, childrenKey, value)
      if (findItem) return findItem
    }
  }
}

// 修改浏览器标题
export const changeDocumentTitle = (title?: string) => {
  document.title = title ? `${title}-${defaultSettings.title}` : defaultSettings.title
}

// 过滤字符串左右空格
export const handleTrim = (val: string): string => val?.trim?.()

// 树形 过滤、加属性
/**
 * @param {array} dataSource 数据源
 * @param {array} titleKeys 生成title的key数组
 * @param {string} key node唯一key值
 * @param {string} valueKey node唯一value值
 * @param {string} childrenKey 子级树的key
 * @param {string} disabledKey 是否禁用的判断条件
 * */
export function traceToTreeData(
  dataSource: any[] = [],
  options: {
    titleKeys?: string[]
    key?: string
    valueKey?: string
    childrenKey?: string
    disabledKey?: string
  } = {}
) {
  const {
    titleKeys = ['title'],
    key = 'id',
    valueKey = 'id',
    childrenKey = 'children',
    disabledKey = 'disabled'
  } = options
  return dataSource?.reduce((list, node) => {
    list.push({
      ...node,
      ...{
        title: titleKeys?.map((k) => node[k]).join(''),
        value: node?.[valueKey] || '', // 传值
        key: node[key],
        disabled: node?.[disabledKey],
        children: node?.[childrenKey]?.length
          ? traceToTreeData([...node[childrenKey]], options)
          : [],
        label: titleKeys?.map((k) => node[k]).join('') // 显示
      }
    })
    return list
  }, [])
}

/**
 * 将树打成一维数组
 * @param dataSource 数据源
 * @param childrenKey 子级树的key
 * @param initArray 初始化的转换后数组可不填
 * @returns 过滤后的数组
 */
export function handleTreeTransformArray<T extends { [props: string]: T[] } = any>(
  dataSource: T[],
  childrenKey = 'children',
  initArray: T[] = []
): T[] {
  return dataSource.reduce((arr, item) => {
    arr.push(item)
    if (item?.[childrenKey]?.length && Array.isArray(item?.[childrenKey]))
      handleTreeTransformArray(item?.[childrenKey]!, childrenKey, arr)
    return arr
  }, initArray)
}

/**
 * 下载文件流成文件提示的公共方法
 * @param fileName 需要显示的文件名(带扩展名)
 * @param blob 文件流
 * @param filetype 文件类型,默认excel
 */
export const DownloadAttachment = (
  fileName: string,
  blob: Blob,
  filetype = 'application/vnd.ms-excel'
) => {
  if (blob) {
    if (window.navigator && (window.navigator as any).msSaveOrOpenBlob) {
      (window.navigator as any).msSaveOrOpenBlob(new Blob([blob], { type: filetype }), fileName)
    } else {
      const link = document.createElement('a')
      const binaryData = []
      binaryData.push(blob)
      link.href = window.URL.createObjectURL(new Blob(binaryData, { type: filetype }))
      link.download = fileName
      // 此写法兼容可火狐浏览器
      document.body.appendChild(link)
      const evt = document.createEvent('MouseEvents')
      evt.initEvent('click', false, false)
      link.dispatchEvent(evt)
      document.body.removeChild(link)
    }
  }
}

// 将驼峰命名法转换为下划线法命名法
export const transHump = (v: string) => v.replace(/([A-Z])/g, '_$1').toLowerCase()

// 处理枚举值显示
export const handleEnumValue = (
  enumObj: Record<string | number, string>,
  enumKey: string | number
) => enumObj?.[enumKey] || enumKey

/***
 * 格式化日期为对象
 */
export const dateFormatObj = (d: any) => {
  if (!d) {
    return {
      year: '',
      month: '',
      date: '',
      hours: '',
      minutes: ''
    }
  }
  const myDate = new Date(d)
  let month: number | string = myDate.getMonth() + 1
  let date: number | string = myDate.getDate()
  let hours: number | string = myDate.getHours()
  let minutes: number | string = myDate.getMinutes()
  month = month > 9 ? month : `0${month}`
  date = date > 9 ? date : `0${date}`
  hours = hours > 9 ? hours : `0${hours}`
  minutes = minutes > 9 ? minutes : `0${minutes}`
  return {
    year: myDate.getFullYear(),
    month,
    date,
    hours,
    minutes
  }
}

export const Base64 = {
  _keyStr: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=',
  encode: function (input: string) {
    let output = ''
    let chr1, chr2, chr3, enc1, enc2, enc3, enc4
    let i = 0
    input = Base64._utf8_encode(input)
    while (i < input.length) {
      chr1 = input.charCodeAt(i++)
      chr2 = input.charCodeAt(i++)
      chr3 = input.charCodeAt(i++)
      enc1 = chr1 >> 2
      enc2 = ((chr1 & 3) << 4) | (chr2 >> 4)
      enc3 = ((chr2 & 15) << 2) | (chr3 >> 6)
      enc4 = chr3 & 63
      if (isNaN(chr2)) {
        enc3 = enc4 = 64
      } else if (isNaN(chr3)) {
        enc4 = 64
      }
      output =
        output +
        Base64._keyStr.charAt(enc1) +
        Base64._keyStr.charAt(enc2) +
        Base64._keyStr.charAt(enc3) +
        Base64._keyStr.charAt(enc4)
    }
    return output
  },

  decode: function (input: string) {
    let output = ''
    let chr1, chr2, chr3
    let enc1, enc2, enc3, enc4
    let i = 0
    input = input.replace(/[^A-Za-z0-9+/=]/g, '')
    while (i < input.length) {
      enc1 = Base64._keyStr.indexOf(input.charAt(i++))
      enc2 = Base64._keyStr.indexOf(input.charAt(i++))
      enc3 = Base64._keyStr.indexOf(input.charAt(i++))
      enc4 = Base64._keyStr.indexOf(input.charAt(i++))
      chr1 = (enc1 << 2) | (enc2 >> 4)
      chr2 = ((enc2 & 15) << 4) | (enc3 >> 2)
      chr3 = ((enc3 & 3) << 6) | enc4
      output = output + String.fromCharCode(chr1)
      if (enc3 !== 64) {
        output = output + String.fromCharCode(chr2)
      }
      if (enc4 !== 64) {
        output = output + String.fromCharCode(chr3)
      }
    }
    output = Base64._utf8_decode(output)
    return output
  },
  _utf8_encode: function (string: string) {
    string = string.replace(/\r\n/g, '\n')
    let utftext = ''
    for (let n = 0; n < string.length; n++) {
      const c = string.charCodeAt(n)
      if (c < 128) {
        utftext += String.fromCharCode(c)
      } else if (c > 127 && c < 2048) {
        utftext += String.fromCharCode((c >> 6) | 192)
        utftext += String.fromCharCode((c & 63) | 128)
      } else {
        utftext += String.fromCharCode((c >> 12) | 224)
        utftext += String.fromCharCode(((c >> 6) & 63) | 128)
        utftext += String.fromCharCode((c & 63) | 128)
      }
    }
    return utftext
  },
  _utf8_decode: function (utftext: string) {
    let string = ''
    let i = 0
    let c = 0
    let c1 = 0
    let c2 = 0
    while (i < utftext.length) {
      c = utftext.charCodeAt(i)
      if (c < 128) {
        string += String.fromCharCode(c)
        i++
      } else if (c > 191 && c < 224) {
        c1 = utftext.charCodeAt(i + 1)
        string += String.fromCharCode(((c & 31) << 6) | (c1 & 63))
        i += 2
      } else {
        c1 = utftext.charCodeAt(i + 1)
        c2 = utftext.charCodeAt(i + 2)
        string += String.fromCharCode(((c & 15) << 12) | ((c1 & 63) << 6) | (c2 & 63))
        i += 3
      }
    }
    return string
  }
}
